using System;
using Habanero.Base;
using Habanero.BO;

namespace FireStarter.Base.BusinessObjectMerger
{
    public class BusinessObjectTreeTraverser
    {
        public void TraverseTree(IBusinessObject businessObject, Action<IBusinessObject> businessObjectTreeVisitorDelegate)
        {
            TraverseTree(businessObject, -1, businessObjectTreeVisitorDelegate);
        }

        public void TraverseTree(IBusinessObject businessObject, int levelsToTraverse, Action<IBusinessObject> businessObjectTreeVisitorDelegate)
        {
            //businessObjectTreeVisitorDelegate(businessObject);
            BusinessObjectRelationshipTraverser businessObjectRelationshipTraverser = new BusinessObjectRelationshipTraverser();
            BusinessObjectRelationshipTraverser.BusinessObjectRelationshipVisitorDelegate relationshipVisitorDelegate = null;
            relationshipVisitorDelegate = CreateRecursiveRelationshipTraverserDelegate(businessObjectRelationshipTraverser, businessObjectTreeVisitorDelegate, levelsToTraverse);
            businessObjectRelationshipTraverser.TraverseChildren(businessObject, relationshipVisitorDelegate);
        }

        private static BusinessObjectRelationshipTraverser.BusinessObjectRelationshipVisitorDelegate CreateRecursiveRelationshipTraverserDelegate(BusinessObjectRelationshipTraverser businessObjectRelationshipTraverser, Action<IBusinessObject> businessObjectTreeVisitorDelegate, int levelsToTraverse)
        {
            return delegate(IBusinessObject bo, IRelationship relationship)
                       {
                           if (levelsToTraverse == 0) return;
                           BusinessObjectRelationshipTraverser.BusinessObjectRelationshipVisitorDelegate recursiveRelationshipTraverserDelegate =
                               CreateRecursiveRelationshipTraverserDelegate(businessObjectRelationshipTraverser, businessObjectTreeVisitorDelegate, levelsToTraverse - 1);
                           IMultipleRelationship multipleRelationship = relationship as IMultipleRelationship;
                           if (multipleRelationship != null)
                               foreach (IBusinessObject childBo in multipleRelationship.BusinessObjectCollection)
                               {
                                   businessObjectTreeVisitorDelegate(childBo);
                                   businessObjectRelationshipTraverser.TraverseChildren(childBo, recursiveRelationshipTraverserDelegate);
                               }
                           ISingleRelationship singleRelationship = relationship as ISingleRelationship;
                           if (singleRelationship != null)
                           {
                               IBusinessObject childBo = singleRelationship.GetRelatedObject();
                               if (childBo == null) return;
                               businessObjectTreeVisitorDelegate(childBo);
                               businessObjectRelationshipTraverser.TraverseChildren(childBo, recursiveRelationshipTraverserDelegate);
                           }
                       };
        }
    }
}